// @ts-nocheck

import { Component, Vue, Prop, Emit, Watch } from 'vue-property-decorator';
import Map from 'ol/Map';
import View from 'ol/View';
import Feature from 'ol/Feature';
import TileGrid from 'ol/tilegrid/TileGrid';
import Tile from 'ol/layer/Tile';
import VectorLayer from 'ol/layer/Vector';
import HeatMap from 'ol/layer/Heatmap';
import XYZ from 'ol/source/XYZ';
import TileImage from 'ol/source/TileImage';
import Style from 'ol/style/Style';
import Icon from 'ol/style/Icon';
import Fill from 'ol/style/Fill';
import CircleStyle from 'ol/style/Circle';
import Stroke from 'ol/style/Stroke';
import Text from 'ol/style/Text';
import Point from 'ol/geom/Point';
import LineString from 'ol/geom/LineString';
import LinearRing from 'ol/geom/LinearRing';
import Zoom from 'ol/control/Zoom';
import FullScreen from 'ol/control/FullScreen';
import * as _ol_control_ from 'ol/control';
import * as _ol_interaction_ from 'ol/interaction';
import * as _ol_proj_ from 'ol/proj';
import Projection from 'ol/proj/Projection';
import * as _ol_extent_ from 'ol/extent';
import VectorSource from 'ol/source/Vector.js';
import GeoJSON from 'ol/format/GeoJSON.js';
import Draw from 'ol/interaction/Draw';
import Overlay from 'ol/Overlay';
import { MultiLineString, MultiPoint, MultiPolygon, Polygon } from 'ol/geom';
import { getArea, getLength } from 'ol/sphere';
import OL3Parser from 'jsts/org/locationtech/jts/io/OL3Parser';

import * as CommonService from '@/service/common-service';
@Component({})
export default class ComMap extends Vue {
  @Prop({
    required: false,
    default: '',
  }) mapConfigName!: any
  _mapConfigName: any;

  @Prop({
    required: false,
    default: () => true,
  }) initFlag!: any

  @Prop({
    required: false,
    default: 'dom_map',
  }) domID!: any;

  public mapcore: any = '';
  private markHandler: any = '';
  private defaultVectorLayer: any = '';
  private mapClickHandler: any = '';
  private draw: any = '';
  private mapConfig: any = '';
  pointMarker: any = '';
  view: any;
  sketch: any;
  helpTooltipElement: any;
  helpTooltip: any;
  measureTooltipElement: any;
  measureTooltip: any;
  continuePolygonMsg = 'Click to continue drawing the polygon';
  continueLineMsg = 'Click to continue drawing the line';
  listener: any;
  ERD: any;

  mounted() {
    this.$nextTick(() => {
      let elementResizeDetectorMaker = require("element-resize-detector");
      this.ERD = elementResizeDetectorMaker();
      this.ERD.listenTo(document.querySelector('.main-map'), this.updateMapSize);
    });
  }

  beforeDestroy() {
    this.ERD.uninstall(this.mainTable);
  }

  @Watch('mapConfigName', { immediate: true })
  onChangeMapConfigName(val) {
    // 如果在路由中指定了配置，则使用指定的配置，若未指定，则使用后台的配置
    let urlMap = this.$route.query.mapConfigName, sessionMap = JSON.parse(sessionStorage.getItem('sysConfigMap') as any).MAPCONFIG_NAME;
    this._mapConfigName = urlMap ? urlMap : val ? val : sessionMap ? sessionMap : 'mapconfig.json';
    this.$nextTick(() => this.init());
    // this.init()
  }

  init() {
    CommonService.getMapConfig('/map-config/' + this._mapConfigName).then((data: any) => {
      this.mapConfig = data;
      if (this.initFlag) {
        let tileExtent = this.mapConfig.mapExtent.split(',');
        let initExtent = this.mapConfig.initExtent.split(',');
        let projectionName = 'EPSG:' + this.mapConfig.spatialRef;
        let projection = _ol_proj_.get(projectionName);
        if (!projection) {
          let units = 'm';
          projection = new Projection({ code: 'urn:ogc:def:crs:EPSG::' + this.mapConfig.spatialRef, units: units });
          _ol_proj_.addProjection(projection);
          projection = new Projection({ code: projectionName, units: units });
          _ol_proj_.addProjection(projection);
        }
        this.mapcore = new Map({
          target: this.domID,
          view: new View({
            center: [(Number(tileExtent[0]) + Number(tileExtent[2])) / 2, (Number(tileExtent[1]) + Number(tileExtent[3])) / 2],
            minZoom: 2,
            maxZoom: this.mapConfig.maxZoom,
            zoom: 2,
            projection: projection
          }),
          controls: _ol_control_.defaults(),
          interactions: _ol_interaction_.defaults({ altShiftDragRotate: false, pinchRotate: false })
        });
        // 添加栅格瓦片图层
        if (this.mapConfig.tileLayers) {
          for (let i = 0; i < this.mapConfig.tileLayers.length; i++) {
            let layerInfo: any = this.mapConfig.tileLayers[i];
            let layer: any;
            if (this.mapConfig.tileLayers[i].mapServerType === 1) {
              layer = this.createXYZTileLayer(layerInfo);
            } else if (this.mapConfig.tileLayers[i].mapServerType === 4) {
              layer = this.createBaiduTileLayer(layerInfo);
            }
            this.mapcore.addLayer(layer);
          }
        }
        // 添加矢量图层
        if (this.mapConfig.vectorLayers) {
          for (let i = 0; i < this.mapConfig.vectorLayers.length; i++) {
            let layerInfo: any = this.mapConfig.vectorLayers[i];
            let layer: any;
            layer = this.createVectorLayer(layerInfo);
            this.mapcore.addLayer(layer);
          }
        }
        this.mapcore.getView().fit([Number(initExtent[0]), Number(initExtent[1]), Number(initExtent[2]), Number(initExtent[3])], this.mapcore.getSize());
        // let zoom = new Zoom();
        // this.mapcore.addControl(zoom);
        let fullScreen = new FullScreen();
        this.mapcore.addControl(fullScreen);
        this.defaultVectorLayer = this.addVectorLayer('defaultVectorLayer');
        this.onMapLoaded({ mapcore: this.mapcore });
      }
    });
  }


  @Emit('onMapLoaded')
  onMapLoaded(params) {
    this.$nextTick(() => params);
    // return params;
  }

  public createVectorLayer(layerInfo: any) {
    let style = new Style({
      fill: new Fill({
        color: 'rgba(5, 29, 82, 0.6)'
      }),
      stroke: new Stroke({
        color: 'rgba(255, 255, 255, 0.6)',
        width: 1
      }),
      text: new Text({ fill: new Fill({ color: '#ffffff' }) })
    });

    return new VectorLayer({
      renderMode: 'image',
      source: new VectorSource({
        url: layerInfo.mapServerUrl,
        format: new GeoJSON()
      }),
      style: function (feature) {
        style.getText().setText(feature.get('name'));
        return style;
      }
    });
  }

  public createXYZTileLayer(layerInfo: any) {
    // 获取地图范围
    let tileExtent = layerInfo.tile.mapExtent.split(',');
    tileExtent = tileExtent.map(s => +s);
    // 获取地图分辨率
    let resolutions = layerInfo.tile.mapResolution.split(',');
    resolutions = resolutions.map(s => +s);
    let tileGrid = new TileGrid({
      extent: tileExtent,
      resolutions: resolutions,
      origin: [layerInfo.tile.origionPtX, layerInfo.tile.origionPtY],
      tileSize: layerInfo.tile.tileSize
    });

    let serviceUrl = layerInfo.mapServerUrl;

    let projectionName = 'EPSG:' + layerInfo.tile.spatialRef;
    let projection = _ol_proj_.get(projectionName);
    if (!projection) {
      let units = 'm';
      projection = new Projection({ code: 'urn:ogc:def:crs:EPSG::' + this.mapConfig.tile.spatialRef, units: units });
      _ol_proj_.addProjection(projection);
      projection = new Projection({ code: projectionName, units: units });
      _ol_proj_.addProjection(projection);
    }
    let that = this;
    return new Tile({
      source: new XYZ({
        tileGrid: tileGrid,
        projection: projection,
        tileUrlFunction: function (tileCoord) {
          let x = tileCoord[1].toString();
          let y = (-tileCoord[2] - 1).toString();
          let z = tileCoord[0].toString();
          if (layerInfo.tileType === 1) {
            x = 'C' + that.zeroFill(tileCoord[1], 8, 16);
            y = 'R' + that.zeroFill(-tileCoord[2] - 1, 8, 16);
            z = 'L' + that.zeroFill(tileCoord[0], 2, 10);
          }
          let url = serviceUrl.replace(/{z}/g, z)
            .replace('{x}', x)
            .replace('{y}', y);
          return url;
        },
        url: layerInfo.mapServerUrl
      })
    });
  }

  // 给8位字符串文件名补0
  private zeroFill(num: number, len: number, radix: number) {
    let str = num.toString(radix || 10);
    while (str.length < len) {
      str = '0' + str;
    }
    return str;
  }

  private createBaiduTileLayer(layerInfo: any) {
    let projection = _ol_proj_.get('EPSG:3857');
    let resolutions = [];
    for (let i = 0; i < 20; i++) {
      resolutions[i] = Math.pow(2, 18 - i);
    }
    let tileGrid = new TileGrid({
      origin: [0, 0],
      resolutions: resolutions
    });
    let baidu_source = new TileImage({
      projection: projection,
      tileGrid: tileGrid,
      tilePixelRatio: 1, // 在高分辨率设备上必须设置此项
      tileUrlFunction: function (tileCoord, pixelRatio, proj) {
        if (!tileCoord) {
          return '';
        }
        let z = tileCoord[0];
        let x = tileCoord[1];
        let y = tileCoord[2];

        if (x < 0) {
          x = 'M' + (-x);
        }
        if (y < 0) {
          y = 'M' + (-y);
        }
        return layerInfo.mapServerUrl.replace(/{z}/g, z)
          .replace('{x}', x)
          .replace('{y}', y);
      }
    });

    return new Tile({
      source: baidu_source
    });
  }

  public addVectorLayer(layerID, map: any = null) {
    let mapCore = map === null ? this.mapcore : map;
    let vectorSource = new VectorSource({
      features: []
    });
    let vectorLayer = new VectorLayer({
      source: vectorSource,
    });
    vectorLayer.set('layerID', layerID);
    mapCore.addLayer(vectorLayer);
    return vectorLayer;
  }

  /**
      * 在指定图层上添加GeoJson对象
      * @param vectorLayer
      * @param geoJson
      */
  public addGeoJsonObjectByLayer(vectorLayer, geoJson, styleJson) {
    let fs = (new GeoJSON()).readFeatures(geoJson);
    vectorLayer.getSource().addFeatures(fs);
    if (!styleJson) {
      return;
    }
    let image = new CircleStyle({
      radius: styleJson['Point'].image.radius,
      fill: new Fill({
        color: styleJson['Point'].image.fill.color
      }),
      stroke: new Stroke({
        color: styleJson['Point'].image.stroke.color,
        width: styleJson['Point'].image.stroke.width
      })
    });
    let styles = {
      'Point': new Style({
        image: image
      }),
      'LineString': new Style({
        stroke: new Stroke({
          color: styleJson['LineString'].stroke.color,
          width: styleJson['LineString'].stroke.width
        })
      }),
      'MultiLineString': new Style({
        stroke: new Stroke({
          color: styleJson['LineString'].stroke.color,
          width: styleJson['LineString'].stroke.width
        })
      }),
      'MultiPoint': new Style({
        image: image
      }),
      'MultiPolygon': new Style({
        stroke: new Stroke({
          color: styleJson['Polygon'].stroke.color,
          width: styleJson['Polygon'].stroke.width
        }),
        fill: new Fill({
          color: styleJson['Polygon'].fill.color
        })
      }),
      'Polygon': new Style({
        stroke: new Stroke({
          color: styleJson['Polygon'].stroke.color,
          lineDash: styleJson['Polygon'].stroke.lineDash,
          width: styleJson['Polygon'].stroke.width
        }),
        fill: new Fill({
          color: styleJson['Polygon'].fill.color
        })
      }),
      'GeometryCollection': new Style({
        stroke: new Stroke({
          color: styleJson['Polygon'].stroke.color,
          width: styleJson['Polygon'].stroke.width
        }),
        fill: new Fill({
          color: styleJson['Polygon'].fill.color
        }),
        image: image
      }),
      'Circle': new Style({
        stroke: new Stroke({
          color: styleJson['Circle'].stroke.color,
          width: styleJson['Circle'].stroke.width
        }),
        fill: new Fill({
          color: styleJson['Circle'].fill.color
        })
      })
    };
    let styleFunction = function (feature) {
      return styles[feature.getGeometry().getType()];
    };
    vectorLayer.setStyle(styleFunction);
  }

  /**
   * 在默认图层上添加GeoJson对象
   * @param geoJson
   */
  public addGeoJsonObject(geoJson, styleJson) {
    this.addGeoJsonObjectByLayer(this.defaultVectorLayer, geoJson, styleJson);
  }

  /** 清除弹窗 */
  public clearOverlays() {
    this.mapcore.getOverlays().clear();
  }

  /**
   * 在默认图层上添加点
   * @param vectorLayer
   * @param points
   */
  public addPoints(points) {
    this.clearDefaultVectorLayer();
    this.addPointsByLayer(this.defaultVectorLayer, points);
  }

  /**
   * 设置图层的样式
   * @param styleFunction
   * @param layer
   */
  public setLayerStyle(styleFunction, layer) {
    layer = (layer == null ? this.defaultVectorLayer : layer);
    layer.setStyle(styleFunction);
  }

  /**
   * 使用json创建OpenLayer的Style
   * @param styleJson
   */
  public createOLStyle(styleJson) {
    let image = null;
    let stroke = null;
    let fill = null;
    let text = null;
    if (styleJson['image']) {
      image = new CircleStyle({
        radius: styleJson.image.radius,
        fill: new Fill({
          color: styleJson.image.fill.color
        }),
        stroke: new Stroke({ color: styleJson.image.stroke.color, width: styleJson.image.stroke.width })
      });
    }
    if (styleJson.stroke) {
      stroke = new Stroke({
        color: styleJson.stroke.color,
        width: styleJson.stroke.width
      });
    }
    if (styleJson.fill) {
      fill = new Fill({
        color: styleJson.fill.color
      });
    }
    if (styleJson.text) {
      text = new Text({
        // 位置
        textAlign: styleJson.text.textAlign || 'center',
        // 基准线
        textBaseline: styleJson.text.textBaseline || 'middle',
        font: styleJson.text.font || '14px Microsoft YaHei',
        offsetX: styleJson.text.offsetX || 0,
        offsetY: styleJson.text.offsetY || -15,
        text: styleJson.text.text || '',
        fill: new Fill({
          color: styleJson.text.fill.color || '#fff'
        }),
        placement: styleJson.text.placement || 'point',
        overflow: styleJson.text.overflow || false
      });
    }
    let style = new Style({
      stroke: stroke,
      fill: fill,
      image: image,
      text: text
    });
    return style;
  }

  /**
   * 在指定图层上添加点
   * @param vectorLayer
   * @param points
   */
  public addPointsByLayer(vectorLayer, points) {
    for (let i = 0; i < points.length; i++) {
      let feature = new Feature({
        geometry: new Point([points[i].geometry.x, points[i].geometry.y]),
      });
      if (points[i].attr) {
        feature.setProperties(points[i].attr);
      }
      let text = null;
      if (points[i].text) {
        text = new Text({
          // 位置
          textAlign: points[i].text.textAlign || 'center',
          // 基准线
          textBaseline: points[i].text.textBaseline || 'middle',
          font: points[i].text.font || '14px Microsoft YaHei',
          offsetX: points[i].text.offsetX || 0,
          offsetY: points[i].text.offsetY || -15,
          text: points[i].text.text || '',
          fill: new Fill({
            color: points[i].text.fill.color || '#fff'
          })
        });
      }
      let iconStyles = [];
      if (points[i].style.styleType === 1) { // 叠加人员头像的定位图标
        let style = new Style({
          image: new Icon({
            anchor: [0.5, 64],
            anchorXUnits: 'fraction',
            anchorYUnits: 'pixels',
            src: 'image/location.svg'
          }),
          text: text
        });
        iconStyles.push(style);
        if (points[i].style.humanIconUrl) {
          let headStyle = new Style({
            image: new Icon({
              anchor: [0.5, 170],
              anchorXUnits: 'fraction',
              anchorYUnits: 'pixels',
              src: points[i].style.humanIconUrl,
              scale: 0.3
            })
          });
          iconStyles.push(headStyle);
        }
        feature.setStyle(iconStyles);
        vectorLayer.getSource().addFeature(feature);
      } else if (points[i].style.styleType === 2) {
        let style = new Style({
          image: new CircleStyle({
            radius: points[i].style.radius,
            fill: new Fill({
              color: points[i].style.fillColor
            })
          }),
          text: text
        });
        iconStyles.push(style);
        let locStyle = new Style({
          image: new Icon({
            anchor: [0.5, 30],
            anchorXUnits: 'fraction',
            anchorYUnits: 'pixels',
            src: points[i].style.iconUrl
          }),
          text: text
        });
        iconStyles.push(locStyle);
        feature.setStyle(iconStyles);
        vectorLayer.getSource().addFeature(feature);
      } else if (points[i].style.styleType === 3) {
        let style = new Style({
          image: new Icon({
            anchor: [0.5, 40],
            anchorXUnits: 'fraction',
            anchorYUnits: 'pixels',
            src: 'image/patrol.png'
          }),
          text: text
        });
        feature.setStyle(style);
        vectorLayer.getSource().addFeature(feature);
      } else if (points[i].style.styleType === 4) {
        // this.addPatrolPoints(vectorLayer, feature, points[i].attr.N);
      } else if (points[i].style.styleType === 5) { // 轨迹起点和终点样式
        let onterStyle = new Style({
          image: new CircleStyle({
            radius: points[i].style.radius * 5,
            fill: new Fill({
              color: points[i].style.backColor
            })
          })
        });
        let midStyle = new Style({
          image: new CircleStyle({
            radius: points[i].style.radius * 1.5,
            fill: new Fill({
              color: 'white'
            })
          }),
        });
        let innerStyle = new Style({
          image: new CircleStyle({
            radius: points[i].style.radius,
            fill: new Fill({
              color: points[i].style.fillColor
            })
          })
        });
        iconStyles.push(onterStyle);
        iconStyles.push(midStyle);
        iconStyles.push(innerStyle);
        feature.setStyle(iconStyles);
        vectorLayer.getSource().addFeature(feature);
      } else if (points[i].style.styleType === 6) {
        let style = new Style({
          image: new CircleStyle({
            radius: points[i].style.radius * 8,
            fill: new Fill({
              color: points[i].style.fillColor
            })
          }),
          text: text
        });
        iconStyles.push(style);
        feature.setStyle(iconStyles);
        vectorLayer.getSource().addFeature(feature);
      }
    }
  }

  /** 热力图 */
  public addHeatMapPoints(heatMapLayer, points) {
    let features = [];
    for (let i = 0; i < points.length; i++) {
      let feature = new Feature({
        geometry: new Point([points[i].x, points[i].y])
      });
      features.push(feature);
    }
    heatMapLayer.getSource().addFeatures(features);
  }

  public addLineString(vectorLayer, lineString) {
    let feature = new Feature({
      geometry: new LineString(lineString.geometry)
    });
    feature.setStyle(new Style({
      stroke: new Stroke({
        width: lineString.style.width,
        color: lineString.style.color
      })
    }));
    vectorLayer.getSource().addFeature(feature);
    return feature;
  }

  // 轨迹绘画
  public drawTrack(vectorLayer, trackList) {
    let pointGeometries = [];
    let pointFeatures = [];
    // 起点和终点要素
    let startPointFeature = {
      geometry: { 'x': trackList[0].X, 'y': trackList[0].Y },
      attr: trackList[0],
      style: { styleType: 5, fillColor: [30, 144, 255, 1], backColor: [30, 144, 255, 0.2], radius: 8 }
    };
    pointFeatures.push(startPointFeature);
    let length = trackList.length;
    let endPointFeature = {
      geometry: { 'x': trackList[length - 1].X, 'y': trackList[length - 1].Y },
      attr: trackList[length - 1],
      style: { styleType: 5, fillColor: [148, 0, 211, 1], backColor: [148, 0, 211, 0.2], radius: 8 }
    };
    pointFeatures.push(endPointFeature);
    // 轨迹线要素
    for (let i = 0; i < trackList.length; i++) {
      pointGeometries.push([trackList[i].X, trackList[i].Y]);
    }
    let lineString = {
      geometry: pointGeometries,
      attr: '',
      style: { width: 6, color: [30, 144, 255, 1] }
    };
    this.pointMarker = {
      geometry: { 'x': trackList[0].X, 'y': trackList[0].Y },
      attr: trackList[0],
      style: { styleType: 2, radius: 5, fillColor: '#ff0000', iconUrl: '/assets/images/location.png' }
    };
    this.addPoints([this.pointMarker]);
    // 渲染轨迹
    this.addPointsByLayer(vectorLayer, pointFeatures);
    let feature = this.addLineString(vectorLayer, lineString);
    this.mapcore.getView().fit(feature.getGeometry());
  }

  /**范围*/
  public fitExtent(extent, map: any = null) {
    let mapCore = map === null ? this.mapcore : map;
    let num = this.mapConfig.tileLayers[0].tile.spatialType === 1 ? 0.007 : 500;
    if (extent[0] === extent[2] && extent[1] === extent[3]) {
      mapCore.getView().fit([+extent[0] - num, +extent[1] - num, +extent[2] + num, +extent[3] + num], { duration: 500 });
    } else {
      mapCore.getView().fit(extent, { duration: 500 });
    }
  }

  /**
* 在地图上设置标记
* @param callback
*/
  public setMark(context, callback) {
    let that = this;
    this.markHandler = function (evt) {
      let point = {
        geometry: { x: evt.coordinate[0], y: evt.coordinate[1] },
        style: { styleType: 2, radius: 5, fillColor: '#ff0000', iconUrl: '/assets/images/location.png' }
      };
      that.addPoints([point]);
      callback(context, evt);
    };
    this.mapcore.on('singleclick', this.markHandler);
  }

  /**
   * 结束在地图上设置标记
   * @param callback
   */
  public endMark() {
    this.mapcore.un('singleclick', this.markHandler);
  }

  public addMapClickEvent(context, callback, map: any = null) {
    let that = this;
    let mapCore = map === null ? this.mapcore : map;
    this.mapClickHandler = function (evt) {
      let coordinate = evt.coordinate;
      let features = mapCore.getFeaturesAtPixel(evt.pixel);
      let zoom = evt.map.getView().getZoom();
      callback(context, { 'coordinate': coordinate, 'features': features, 'zoom': zoom });
    };
    mapCore.on('click', this.mapClickHandler);
  }

  public removeMapClickEvent() {
    this.mapcore.un('click', this.mapClickHandler);
  }

  /**
   * 清空默认的图层
   */
  public clearDefaultVectorLayer() {
    this.defaultVectorLayer.getSource().clear();
  }

  /**
   * 清空图层，并移除
   * @param LayerId
   */
  public clearVectorLayerByLayerId(LayerId) {
    if (this[LayerId]) {
      this[LayerId].getSource().clear();
      this.mapcore.removeLayer(this[LayerId]);
    }
  }

  /**
   * 开始绘制几何图形
   * @param geoType 几何类型，包括，'Point', 'LineString', 'LinearRing', 'Polygon', 'MultiPoint', 'MultiLineString', 'MultiPolygon', 'GeometryCollection', 'Circle'
   * @param drawEndCallback 绘制完成后的回调函数
   */
  public startDraw(geoType, drawEndCallback, self) {
    this.draw = new Draw({
      source: this.defaultVectorLayer.getSource(),
      type: geoType
    });
    this.mapcore.addInteraction(this.draw);
    this.draw.on('drawend', function (evt) {
      drawEndCallback(evt.feature.getGeometry(), self);
    });
  }

  /**
   * 结束绘制几何图形
   */
  public endDraw() {
    this.mapcore.removeInteraction(this.draw);
  }

  /**
   * 适应图层视野
   * @param layer 图层对象 设置为null时默认为defaultVectorLayer
   */
  public fitLayerExtent(layer, map = null) {
    layer = (layer == null ? this.defaultVectorLayer : layer);
    this.fitExtent(layer.getSource().getExtent(), map);
  }

  /**
   * 创建 Overlay 叠加层显示弹窗
   * @param element
   */
  public addOverlay(element, autoPan) {
    let overlay = new Overlay({
      element: element, // dom对象
      autoPan: autoPan || true, // 自动平移
      positioning: 'bottom-center',
      stopEvent: false,
      autoPanAnimation: {
        duration: 500 // 动画时间
      }
    });
    this.mapcore.addOverlay(overlay);
    return overlay;
  }

  /**
   *  地图缩放事件
   * @param context
   * @param callback
   */
  public moveendMap(context, callback) {
    this.mapcore.on('moveend', (evt) => {
      let map = evt.map;
      let zoom = map.getView().getZoom();
      let extent = map.getView().calculateExtent(map.getSize());
      callback(context, { zoom: zoom, extent: extent });
    });
  }

  /** 鼠标悬浮事件 */
  public pointerMove(context, callback, map: any = null) {
    let that = this;
    let mapCore = map === null ? this.mapcore : map;
    mapCore.on('pointermove', (evt) => {
      let coordinate = evt.coordinate;
      let features = mapCore.getFeaturesAtPixel(evt.pixel);
      callback(context, { 'coordinate': coordinate, 'features': features });
    });
  }

  /** 地图视图修改 */
  public viewChange(params) {
    this.mapcore.getView().animate(params);
  }

  /** 设置中心点 */
  public setCenter(point) {
    this.mapcore.getView().animate({ // 只设置需要的属性即可
      center: [point.x, point.y], // 中心点
      zoom: 14, // 缩放级别
      rotation: undefined, // 缩放完成view视图旋转弧度
      duration: 500 // 缩放持续时间，默认不需要设置
    });
    // this.mapcore.getView().fit([,point.x,point.y], this.mapcore.getSize());
  }

  /**
   * 添加格网专题图
   * @param extent 格网范围
   * @param colNum 格网列数
   * @param rowNum 格网行数
   * @param data 数据，[列号，行号，值]
   * @param valueColors [值，颜色]
   */
  addGridCharts(extent, colNum, rowNum, data, valueColors, max) {
    let lngExtent = [extent[0], extent[2]];
    let latExtent = [extent[1], extent[3]];
    let cellSizeCoord = [
      (latExtent[1] - latExtent[0]) / colNum,
      (lngExtent[1] - lngExtent[0]) / rowNum
    ];

    function renderItem(params, api) {
      let context = params.context;
      let lngIndex = api.value(0);
      let latIndex = api.value(1);
      let coordLeftTop = [
        +(lngExtent[0] + lngIndex * cellSizeCoord[0]).toFixed(6),
        +(latExtent[0] + latIndex * cellSizeCoord[1]).toFixed(6)
      ];
      let pointLeftTop = getCoord(params, api, lngIndex, latIndex);
      let pointRightBottom = getCoord(params, api, lngIndex + 1, latIndex + 1);

      return {
        type: 'rect',
        shape: {
          x: pointLeftTop[0],
          y: pointLeftTop[1],
          width: pointRightBottom[0] - pointLeftTop[0],
          height: pointRightBottom[1] - pointLeftTop[1]
        },
        style: api.style({
          stroke: 'rgba(0,0,0,0.1)'
        }),
        styleEmphasis: api.styleEmphasis()
      };
    }

    function getCoord(params, api, lngIndex, latIndex) {
      let coords = params.context.coords || (params.context.coords = []);
      let key = lngIndex + '-' + latIndex;

      // bmap returns point in integer, which makes cell width unstable.
      // So we have to use right bottom point.
      return coords[key] || (coords[key] = api.coord([
        +(lngExtent[0] + lngIndex * cellSizeCoord[0]).toFixed(6),
        +(latExtent[0] + latIndex * cellSizeCoord[1]).toFixed(6)
      ]));
    }

    let option = {
      tooltip: {},
      visualMap: {
        type: 'piecewise',
        splitNumber: 5,
        min: 0,
        max: max,
        calculable: true,
        realtime: false,
        inRange: {
          color: [
            'rgba(180,224,243, .8)', 'rgba(180,224,243, .8)', 'rgba(180,224,243, .8)', 'rgba(180,224,243, .8)', 'rgba(112,180,235,.8)', 'rgba(112,180,235,.8)', 'rgba(112,180,235,.8)', 'rgba(112,180,235,.8)', 'rgba(20,130,229,.8)',
            'rgba(20,130,229,.8)', 'rgba(20,130,229,.8)', 'rgba(20,130,229,.8)', 'rgba(20,130,229,.8)', 'rgba(28,63,191,.8)', 'rgba(7,0,147,.8)', 'rgba(248,248,255, .8)',
            'rgba(205,92,92,.8)', 'rgba(165,42,42,.8)', 'rgba(78,34,34,.8)', 'rgba(205,92,92,.8)', 'rgba(205,92,92,.8)', 'rgba(205,92,92,.8)', 'rgba(205,92,92,.8)',
            'rgba(139,0,0,.8)', 'rgba(128,0,0,.8)', 'rgba(255,0,0,.8)',
            'rgba(255,0,0,.8)', 'rgba(255,0,0,.8)', 'rgba(255,0,0,.8)']
        },
        backgroundColor: '#fff'
        //     type: 'piecewise',
        //     inverse: true,
        //     bottom: 10,
        //     left: 10,
        //     pieces: valueColors,
        //     borderColor: '#ccc',
        //     borderWidth: 2,
        //     backgroundColor: '#eee',
        //     dimension: 2,
        //     inRange: {
        //         opacity: 0.7
        //     }
      },
      series: [
        {
          type: 'custom',
          renderItem: renderItem,
          animation: false,
          emphasis: {
            itemStyle: {
              color: 'yellow'
            }
          },
          encode: {
            tooltip: 2
          },
          data: data
        }
      ]
    };

    let echartslayer = new EChartsLayer(option, {
      hideOnMoving: false,
      hideOnZooming: false,
    });

    echartslayer.appendTo(this.mapcore);

    return echartslayer;
  }

  /**
   * 地图缩放修改
   */
  public updateMapSize() {
    if (!this.mapcore) return;
    this.mapcore.updateSize();
  }

  addMapScatterCharts(geoCoordMap, data, max) {
    let convertData = function (datas) {
      let res = [];
      for (let i = 0; i < datas.length; i++) {
        let geoCoord = geoCoordMap[datas[i].name];
        if (geoCoord) {
          res.push({
            name: datas[i].name,
            value: geoCoord.concat(datas[i].value)
          });
        }
      }
      return res;
    };
    let option = {
      tooltip: {
        trigger: 'item'
      },
      openlayers: {},
      series: [
        {
          // name: 'Top 5',
          type: 'effectScatter',
          data: convertData(data),
          symbolSize: function (val) {
            if (val[2] === 0) {
              return 0;
            }
            let a = (val[2] / max) * 100;
            if (a < 15) {
              return 15;
            } else if (a < 60) {
              return a;
            } else if (a < 70) {
              return a - 5;
            } else if (a < 80) {
              return a - 14;
            } else if (a < 90) {
              return a - 23;
            } else {
              return a - 32;
            }
          },
          encode: {
            value: 2
          },
          showEffectOn: 'render',
          rippleEffect: {
            brushType: 'stroke'
          },
          hoverAnimation: true,
          label: {
            formatter: '{b}',
            position: 'right',
            show: true
          },
          itemStyle: {
            color: 'purple',
            shadowBlur: 10,
            shadowColor: '#333'
          },
          zlevel: 1
        }
      ]
    };
    let echartslayer = new EChartsLayer(option, {
      hideOnMoving: false,
      hideOnZooming: false,
    });
    echartslayer.appendTo(this.mapcore);
    return echartslayer;
  }

  /**热力图图层 */
  public addHeatMapLayer(layerID, map) {
    let mapCore = map === null ? this.mapcore : map;
    let vectorSource = new VectorSource({
      features: []
    });
    let heatMapLayer = new HeatMap({
      source: vectorSource,
      blur: 15,
      radius: 8
    });
    heatMapLayer.set('layerID', layerID);
    mapCore.addLayer(heatMapLayer);
    return heatMapLayer;
  }

  /**
   * 缓冲分析
   */
  public addParser() {
    // let parser = new jsts.io.OL3Parser();
    let parser = new OL3Parser();
    parser.inject(Point, LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon);
    return parser;
  }

  /**
   * 获取中心点
   */
  public getCenter() {
    return this.mapcore.getView().getCenter();
  }

  /**
   * 获取地图实例
   */
  getMap() {
    return this.mapcore;
  }

  /**
   * 视图同步用
   * 获取地图初始化试图
   */
  public getInitView() {
    if (!this.view) {
      this._mapConfigName = this._mapConfigName ? this._mapConfigName : 'mapconfig.json';
      this.http.get('/map-config/' + this._mapConfigName).subscribe(data => {
        this.mapConfig = data;
        let tileExtent = this.mapConfig.mapExtent.split(',');
        let projectionName = 'EPSG:' + this.mapConfig.spatialRef;
        let projection = _ol_proj_.get(projectionName);
        if (!projection) {
          let units = 'm';
          projection = new Projection({ code: 'urn:ogc:def:crs:EPSG::' + this.mapConfig.spatialRef, units: units });
          _ol_proj_.addProjection(projection);
          projection = new Projection({ code: projectionName, units: units });
          _ol_proj_.addProjection(projection);
        }
        this.view = new View({
          center: [(Number(tileExtent[0]) + Number(tileExtent[2])) / 2, (Number(tileExtent[1]) + Number(tileExtent[3])) / 2],
          minZoom: 2,
          maxZoom: this.mapConfig.maxZoom,
          zoom: 2,
          projection: projection
        });
        this.onMapLoaded({ view: this.view });
        // return this.view;
      });
    }
  }

  /**
   * 创建题图
   * @param domId 容器ID
   * @param view 视图
   */
  creatMap(domId, view) {
    let initExtent = this.mapConfig.initExtent.split(',');
    let mapcore = new Map({
      target: domId,
      view: view,
      controls: _ol_control_.defaults(),
      interactions: _ol_interaction_.defaults({ altShiftDragRotate: false, pinchRotate: false })
    });
    // 添加栅格瓦片图层
    if (this.mapConfig.tileLayers) {
      for (let i = 0; i < this.mapConfig.tileLayers.length; i++) {
        let layerInfo: any = this.mapConfig.tileLayers[i];
        let layer: any;
        if (this.mapConfig.tileLayers[i].mapServerType === 1) {
          layer = this.createXYZTileLayer(layerInfo);
        } else if (this.mapConfig.tileLayers[i].mapServerType === 4) {
          layer = this.createBaiduTileLayer(layerInfo);
        }
        mapcore.addLayer(layer);
      }
    }
    // 添加矢量图层
    if (this.mapConfig.vectorLayers) {
      for (let i = 0; i < this.mapConfig.vectorLayers.length; i++) {
        let layerInfo: any = this.mapConfig.vectorLayers[i];
        let layer: any;
        layer = this.createVectorLayer(layerInfo);
        mapcore.addLayer(layer);
      }
    }
    // @ts-ignore
    mapcore.getView().fit([Number(initExtent[0]), Number(initExtent[1]), Number(initExtent[2]), Number(initExtent[3])], mapcore.getSize());
    let zoom = new Zoom();
    mapcore.addControl(zoom);
    this.defaultVectorLayer = this.addVectorLayer('defaultVectorLayer', mapcore);
    return mapcore;
  }

  public addFeatures(layer: any, event: any) {
    let feature = new Feature();
    feature.setGeometry(event);
    feature.setStyle(new Style({
      fill: new Fill({ //矢量图层填充颜色，以及透明度
        color: 'rgba(0,204,219,0.15)'
      }),
      stroke: new Stroke({ //边界样式
        color: 'rgba(0,204,219,1)',
        width: 1
      })
    })
    );
    layer.getSource().addFeatures([feature]);
  }

  // 在地图上线、以及图形
  public startDrawAndCallback(geo: any, drawStartCallback: any, self: any, drawEndCallback: any) {
    let that = this;
    this.draw = new Draw({
      source: self.layTool.getSource(),
      type: geo,
      style: new Style({
        fill: new Fill({
          color: '#2CBBFF',
        }),
        stroke: new Stroke({
          color: '#2CBBFF',
          lineDash: [10, 10],
          width: 2,
        }),
        image: new CircleStyle({
          radius: 5,
          stroke: new Stroke({
            color: '#2CBBFF',
          }),
          fill: new Fill({
            color: '#2CBBFF',
          }),
        }),
      }),
    });
    this.mapcore.addInteraction(this.draw);


    this.createMeasureTooltip(this);
    this.createHelpTooltip(this);

    // this.map.on('pointermove', pointerMoveHandler);

    this.mapcore.getViewport().addEventListener('mouseout', function () {
      that.helpTooltipElement.classList.add('hidden');
    });

    this.draw.on('drawstart', function (evt: any) {
      that.sketch = evt.feature;

      /** @type {import("../src/ol/coordinate.js").Coordinate|undefined} */
      let tooltipCoord = evt.coordinate;

      that.listener = that.sketch.getGeometry().on('change', function (data: any) {
        const geom = data.target;
        let output;
        if (geom instanceof Polygon) {
          output = that.getArea(geom);
          tooltipCoord = geom.getInteriorPoint().getCoordinates();
        } else if (geom instanceof LineString) {
          output = that.getLineLength(geom);
          tooltipCoord = geom.getLastCoordinate();
        }
        that.measureTooltipElement.innerHTML = output;
        that.measureTooltip.setPosition(tooltipCoord);
      });
    });

    this.draw.on('drawend', function (evt: any) {
      drawEndCallback(evt.feature.getGeometry(), self);

      that.measureTooltipElement.className = 'ol-tooltip ol-tooltip-static';
      that.measureTooltip.setOffset([0, -7]);
      that.sketch = null;
      // unset tooltip so that a new one can be created
      that.measureTooltipElement = null;
      that.createMeasureTooltip(that);
      // that.unByKey(that);
    });
  }

  /**
   * 获取线的距离
   * @param line
   */
  getLineLength(line: any) {
    let output, length = 0, opt_options;
    this.mapConfig.tileLayers[0].tile.spatialType === 2 ? opt_options = {} : opt_options = { radius: 6378137, projection: 'EPSG:4326' };
    length = getLength(line, opt_options);
    if (length > 100) {
      output = '<span style="color: #2CBBFF">' + Math.round((length / 1000) * 100) / 100 + ' ' + 'km</span>';
    } else {
      output = '<span style="color: #2CBBFF">' + Math.round(length * 100) / 100 + ' ' + 'm</span>';
    }
    return output;
  }

  /**
   * 获取区域面积
   * @param area
   */
  getArea(polygon: any) {
    let area, opt_options;
    if (this.mapConfig.tileLayers[0].tile.spatialType === 2) {
      // 平面坐标系
      opt_options = {};
    } else {
      opt_options = { radius: 6378137, projection: 'EPSG:4326' };
    }
    area = getArea(polygon, opt_options);
    let output;
    if (area > 10000) {
      output = '<span style="color: #2CBBFF">' + Math.round((area / 1000000) * 100) / 100 + ' ' + 'km<sup>2</sup></span>';
    } else {
      output = '<span style="color: #2CBBFF">' + Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup></span>';
    }
    return output;
  }

  pointerMoveHandler(evt: any) {
    if (evt.dragging) {
      return;
    }
    /** @type {string} */
    let helpMsg = 'Click to start drawing';

    if (this.sketch) {
      const geom = this.sketch.getGeometry();
      if (geom instanceof Polygon) {
        helpMsg = this.continuePolygonMsg;
      } else if (geom instanceof LineString) {
        helpMsg = this.continueLineMsg;
      }
    }

    this.helpTooltipElement.innerHTML = helpMsg;
    this.helpTooltip.setPosition(evt.coordinate);
    this.helpTooltipElement.classList.remove('hidden');
  }

  /**
   * Creates a new help tooltip
   */
  createHelpTooltip(self: any) {
    if (self.helpTooltipElement) {
      self.helpTooltipElement.parentNode.removeChild(self.helpTooltipElement);
    }
    self.helpTooltipElement = document.createElement('div');
    self.helpTooltipElement.className = 'hidden ol-tooltip';
    self.helpTooltip = new Overlay({
      element: self.helpTooltipElement,
      offset: [15, 0],
      positioning: 'center-left',
    });
    self.mapcore.addOverlay(self.helpTooltip);
  }

  /**
   * Creates a new measure tooltip
   */
  createMeasureTooltip(self: any) {
    if (self.measureTooltipElement) {
      self.measureTooltipElement.parentNode.removeChild(self.measureTooltipElement);
    }
    self.measureTooltipElement = document.createElement('div');
    self.measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure';
    self.measureTooltip = new Overlay({
      element: self.measureTooltipElement,
      offset: [0, -15],
      positioning: 'bottom-center',
      stopEvent: false,
      insertFirst: false,
    });
    self.mapcore.addOverlay(self.measureTooltip);
  }

  /**
   * 全屏
   */
  fullScreen() {
    let fullScreenControl = new FullScreen();
    this.mapcore.addControl(fullScreenControl);
  }


}
